iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
Mobile Development

使用 Swift 和公開資訊,打造投資理財的 Apps系列 第 24

D23 - 用 Swift 和公開資訊,打造投資理財的 Apps { 台股成交量實作.3 }

  • 分享至 

  • xImage
  •  

在 KLineViewController 開出的 volumeDataSet 會在 parent vc 推進來前就設定好。

所以我們直接在 KLine VC 裡面操作大盤量的 data 即可。

var volumeDataSet = [TwMarketTradingInfo]()

要讓文字轉成數字,要先開出 TwMarketTradingInfo 在 Charts 上用的屬性

import Foundation

struct TwMarketTradingInfo: Hashable {
    
    let date: Date
    let tradeVolumeString: String
    let tradeValueString: String
    let transactionString: String
    let taiexString: String
    let changeString: String
    
    private var numberFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        return formatter
    }
    
    var value: Double? {
        return numberFormatter.number(from: tradeValueString)?.doubleValue
    }
    
    var volume: Double? {
        return numberFormatter.number(from: tradeValueString)?.doubleValue
    }
    
    var transaction: Double? {
        return numberFormatter.number(from: transactionString)?.doubleValue
    }
    
    var taiex: Double? {
        return numberFormatter.number(from: taiexString)?.doubleValue
    }
    
    var change: Double? {
        return numberFormatter.number(from: changeString)?.doubleValue
    }
}

先進入 ChartsAdapter,我們要讓 volumeDataList 轉成 BarChartData

/// 取得大盤量的 Data
    private func getVolumeBarData(volumeDataList: [TwMarketTradingInfo]) -> BarChartData {
        
        var barDataEntryList = [BarChartDataEntry]()
        
        for (index, info) in volumeDataList.enumerated() {
            
            let y = info.volume ?? 0
            let dataEntry = BarChartDataEntry(x: Double(index), y: y)
            barDataEntryList.append(dataEntry)
        }
        
        let dataSet = BarChartDataSet(entries: barDataEntryList)
        dataSet.drawValuesEnabled = false //如果把數值也列出,圖會非常的雜亂,而且值可以設定在右邊
        dataSet.axisDependency = .right //左方的軸已經設定給加權指數了,所以量的圖要設定在右邊的軸
        
        let data = BarChartData(dataSet: dataSet)
        return data
    }

接著,修改 updateWithMALine 的接口,輸入參數要擴充 volumeDataList

//原來的接口
// func updateWithMALine(stockSticks: [StockKLine], combinedView: UIView) {
// 擴充 volumeDataList
func updateWithMALine(stockSticks: [StockKLine], volumeDataList: [TwMarketTradingInfo], combinedView: UIView) {

然後在實作 combinedData 後,加上 barData

    func updateWithMALine(stockSticks: [StockKLine], volumeDataList: [TwMarketTradingInfo], combinedView: UIView) {
        
        if let combinedView = combinedView as? CombinedChartView {
            
            let ma5DataSet = getMALineData(stockSticks: stockSticks, range: 5, color: .blue)
            let ma10DataSet = getMALineData(stockSticks: stockSticks, range: 10, color: .red)
            let ma20DataSet = getMALineData(stockSticks: stockSticks, range: 20, color: .systemOrange)
            
            let lineData = LineChartData(dataSets: [ma5DataSet, ma10DataSet, ma20DataSet])
            let candleData = getCandleData(stockSticks: stockSticks)
            let barData = getVolumeBarData(volumeDataList: volumeDataList)
            
            let combinedData = CombinedChartData()
            combinedData.lineData = lineData
            combinedData.candleData = candleData
            combinedData.barData = barData
            
            combinedView.data = combinedData
            
            // 這邊有優化空間,請讀者自行優化
            let candleDataEntry = convert(stockStick: stockSticks)
            let dataSet = convert(dataEntry: candleDataEntry)
            updateMaxMin(combinedView, dataSet: dataSet)
            
            let indexDateLabels = getIndexDateLabels(from: stockSticks)
            updateXAxis(combinedView, indexDateLabels: indexDateLabels)
        }
    }

接下來,就去改 KLineViewController 的 setupCandleView()

    private func setupCandleView() {
        
        chartsAdapter.updateWithMALine(stockSticks: kLineDataSet, volumeDataList: volumeDataSet, combinedView: chartView)
    }

出來的結果就像這樣子,還差了一點。

因為資料來源有告訴我們,當日漲還是跌,所以更好的表示,就是當那一天的大盤是漲的,Bar 就是紅色,反之就是綠色。

https://ithelp.ithome.com.tw/upload/images/20211002/20140622DL4QpoF8YY.png

在 BarChartDataSet() 生出來之後,可以設定 [UIColor],去設定顏色。

再擴充 ChartsAdapter,讓這個物件可以得到每一根 bar 的顏色

private func getBarColors(volumeList: [TwMarketTradingInfo]) -> [UIColor] {
    
        let colors = volumeList.map { info -> UIColor in
            
            let change = info.change ?? 0
            if change < 0 {
                return UIColor.systemGreen
            }
            return UIColor.systemRed
        }
        return colors
    }

然後,在從 getVolumeBarData 轉成 DataSet 之後,加上 colors,就完成了。

/// 取得大盤量的 Data
    private func getVolumeBarData(volumeDataList: [TwMarketTradingInfo]) -> BarChartData {
        
        var barDataEntryList = [BarChartDataEntry]()
        
        for (index, info) in volumeDataList.enumerated() {
            
            let y = info.volume ?? 0
            let dataEntry = BarChartDataEntry(x: Double(index), y: y)
            barDataEntryList.append(dataEntry)
        }
        
        let dataSet = BarChartDataSet(entries: barDataEntryList)
        dataSet.drawValuesEnabled = false //如果把數值也列出,圖會非常的雜亂,而且值可以設定在右邊
        dataSet.axisDependency = .right //左方的軸已經設定給加權指數了,所以量的圖要設定在右邊的軸
        
        let colors = getBarColors(volumeList: volumeDataList) //加上顏色
        dataSet.colors = colors
        
        let data = BarChartData(dataSet: dataSet)
        return data
    }

Build 起來試試看。

https://ithelp.ithome.com.tw/upload/images/20211002/201406220pneUl1IZf.png

噹噹! 整個圖被壓縮!

我們得到了軟體工程師的日常禮物「有 bug!」

我們下一篇來解決這個 Charts 沒有照大腦中呈現的方式畫的狀況。


上一篇
D22 - 用 Swift 和公開資訊,打造投資理財的 Apps { 台股成交量實作.2 }
下一篇
D24 - 用 Swift 和公開資訊,打造投資理財的 Apps { 台股成交量實作.4 }
系列文
使用 Swift 和公開資訊,打造投資理財的 Apps37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言